home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
UNIX
/
PASCAL
/
PTOC
/
PTC_P.2
< prev
next >
Wrap
Text File
|
1992-11-23
|
53KB
|
2,502 lines
if sp^.lt = lforwlab then
sp^.lt := llabel
else
error(emuldeflab);
end;
oldlbl := tp
end;
(* Parse declaration and statement-body for prog/subs. *)
procedure pbody(tp : treeptr);
var tq : treeptr;
begin
statlvl := statlvl + 1;
if currsym.st = slabel then
begin
tp^.tsublab := plabel;
linkup(tp, tp^.tsublab)
end
else
tp^.tsublab := nil;
if currsym.st = sconst then
begin
tp^.tsubconst := pconst;
linkup(tp, tp^.tsubconst)
end
else
tp^.tsubconst := nil;
if currsym.st = stype then
begin
tp^.tsubtype := ptype;
linkup(tp, tp^.tsubtype)
end
else
tp^.tsubtype := nil;
if currsym.st = svar then
begin
tp^.tsubvar := pvar;
linkup(tp, tp^.tsubvar)
end
else
tp^.tsubvar := nil;
tp^.tsubsub := nil;
tq := nil;
while (currsym.st = sproc) or (currsym.st = sfunc) do
begin
if tq = nil then
begin
tq := psubs;
tp^.tsubsub := tq
end
else begin
tq^.tnext := psubs;
tq := tq^.tnext
end
end;
linkup(tp, tp^.tsubsub);
checksymbol([sbegin, seof]);
if currsym.st = sbegin then
begin
tp^.tsubstmt := pbegin(false);
linkup(tp, tp^.tsubstmt)
end;
statlvl := statlvl - 1
end;
(* Parse program-declaration. *)
function pprogram : treeptr;
var tp : treeptr;
(* Parse a program parameter id-list. *)
function pprmlist : treeptr;
label 999;
var tp,
tq : treeptr;
din,
dut : idptr;
begin
tp := nil;
din := deftab[dinput]^.tidl^.tsym^.lid;
dut := deftab[doutput]^.tidl^.tsym^.lid;
while (currsym.vid = din) or (currsym.vid = dut) do
begin
(* ignore input/output as parameters so that
they will be bound to stdin/stdout unless
declared as variables *)
if currsym.vid = din then
defnams[dinput]^.lused := true
else
defnams[doutput]^.lused := true;
nextsymbol([scomma, srpar]);
if currsym.st = srpar then
goto 999;
nextsymbol([sid])
end;
tq := newid(currsym.vid);
tq^.tsym^.lt := lpointer;
tp := tq;
nextsymbol([scomma, srpar]);
while currsym.st = scomma do
begin
nextsymbol([sid]);
if currsym.vid = din then
defnams[dinput]^.lused := true
else if currsym.vid = dut then
defnams[doutput]^.lused := true
else begin
tq^.tnext := newid(currsym.vid);
tq := tq^.tnext;
tq^.tsym^.lt := lpointer;
end;
nextsymbol([scomma, srpar])
end;
999:
pprmlist := tp
end;
begin (* pprogram *)
enterscope(nil);
tp := mknode(npgm);
nextsymbol([sid]);
tp^.tstat := statlvl;
tp^.tsubid := mknode(nid);
tp^.tsubid^.tup := tp;
tp^.tsubid^.tsym := mksym(lidentifier);
tp^.tsubid^.tsym^.lid := currsym.vid;
tp^.tsubid^.tsym^.lsymdecl := tp^.tsubid;
linkup(tp, tp^.tsubid);
nextsymbol([slpar, ssemic]);
if currsym.st = slpar then
begin
nextsymbol([sid]);
tp^.tsubpar := pprmlist;
linkup(tp, tp^.tsubpar);
nextsymbol([ssemic])
end
else
tp^.tsubpar := nil;
nextsymbol([slabel, sconst, stype, svar,
sproc, sfunc, sbegin]);
pbody(tp);
checksymbol([sdot]);
tp^.tscope := currscope;
leavescope;
pprogram := tp
end; (* pprogram *)
(* Parse a module. *)
function pmodule : treeptr;
var tp : treeptr;
begin (* pmodule *)
enterscope(nil);
tp := mknode(npgm);
tp^.tstat := statlvl;
tp^.tsubid := nil;
tp^.tsubpar := nil;
pbody(tp);
checksymbol([ssemic]);
tp^.tscope := currscope;
leavescope;
pmodule := tp
end; (* pmodule *)
(* Parse label-clause. *)
function plabel;
var tp,
tq : treeptr;
begin
tq := nil;
repeat
nextsymbol([sinteger]);
if tq = nil then
begin
tq := newlbl;
tp := tq
end
else begin
tq^.tnext := newlbl;
tq := tq^.tnext;
end;
nextsymbol([scomma, ssemic])
until currsym.st = ssemic;
nextsymbol([sconst, stype, svar, sbegin, sproc, sfunc]);
plabel := tp
end;
(* Parse an id-list. *)
function pidlist;
var tp,
tq : treeptr;
begin
tq := newid(currsym.vid);
tq^.tsym^.lt := l;
tp := tq;
nextsymbol([scomma, scolon, seq, srpar]);
while currsym.st = scomma do
begin
nextsymbol([sid]);
tq^.tnext := newid(currsym.vid);
tq := tq^.tnext;
tq^.tsym^.lt := l;
nextsymbol([scomma, scolon, seq, srpar])
end;
pidlist := tp
end;
(* Parse const-clause. *)
function pconst;
var tp,
tq : treeptr;
begin
tq := nil;
nextsymbol([sid]);
repeat
if tq = nil then
begin
tq := mknode(nconst);
tq^.tattr := anone;
tp := tq
end
else begin
tq^.tnext := mknode(nconst);
tq := tq^.tnext;
tq^.tattr := anone
end;
tq^.tidl := pidlist(lidentifier);
checksymbol([seq]);
nextsymbol([sid, schar, sstring, sinteger, sreal,
splus, sminus]);
tq^.tbind := pconstant(true);
nextsymbol([ssemic]);
nextsymbol([sid, stype, svar, sbegin,
sfunc, sproc, seof])
until currsym.st <> sid;
pconst := tp
end;
(* Parse a declared constant or a case-statment const. *)
function pconstant;
var tp,
tq : treeptr;
neg : boolean;
begin
neg := currsym.st = sminus;
if currsym.st in [splus, sminus] then
if realok then
nextsymbol([sid, sinteger, sreal])
else
nextsymbol([sid, sinteger]);
if currsym.st = sid then
tp := oldid(currsym.vid, lidentifier)
else
tp := mklit;
if neg then
begin
tq := mknode(numinus);
tq^.texps := tp;
tp := tq
end;
pconstant := tp
end;
(* Parse a record (or record-variant) declaration. *)
(* Cs is the expected closing symbol, dp the scope. *)
function precord;
label 999;
var tp,
tq,
tl,
tv : treeptr;
tsym : lexsym;
begin
tp := mknode(nrecord);
tp^.tflist := nil;
tp^.tvlist := nil;
tp^.tuid := nil;
tp^.trscope := nil;
if cs = send then
begin
enterscope(dp);
dp := currscope
end;
nextsymbol([sid, scase] + [cs]);
tq := nil;
while currsym.st = sid do
begin
if tq = nil then
begin
tq := mknode(nfield);
tq^.tattr := anone;
tp^.tflist := tq
end
else begin
tq^.tnext := mknode(nfield);
tq := tq^.tnext;
tq^.tattr := anone
end;
tq^.tidl := pidlist(lfield);
checksymbol([scolon]);
leavescope;
tq^.tbind := ptypedef;
enterscope(dp);
if currsym.st = ssemic then
nextsymbol([sid, scase] + [cs])
end;
if currsym.st = scase then
begin
nextsymbol([sid]);
tsym := currsym;
nextsymbol([scolon, sof]);
if currsym.st = scolon then
begin
tv := newid(tsym.vid);
if tq = nil then
begin
tq := mknode(nfield);
tp^.tflist := tq
end
else begin
tq^.tnext := mknode(nfield);
tq := tq^.tnext
end;
tq^.tidl := tv;
tv^.tsym^.lt := lfield;
nextsymbol([sid]);
leavescope;
tq^.tbind := oldid(currsym.vid, lidentifier);
enterscope(dp);
nextsymbol([sof])
end;
tq := nil;
repeat
tv := nil;
repeat
nextsymbol([sid, sinteger, schar, splus,
sminus] + [cs]);
if currsym.st = cs then
goto 999;
if tv = nil then
begin
tv := pconstant(false);
tl := tv
end
else begin
tv^.tnext := pconstant(false);
tv := tv^.tnext
end;
nextsymbol([scolon, scomma])
until currsym.st = scolon;
nextsymbol([slpar]);
if tq = nil then
begin
tq := mknode(nvariant);
tp^.tvlist := tq;
end
else begin
tq^.tnext := mknode(nvariant);
tq := tq^.tnext;
end;
tq^.tselct := tl;
tq^.tvrnt := precord(srpar, dp)
until currsym.st = cs
end;
999:
if cs = send then
begin
tp^.trscope := dp;
leavescope
end;
nextsymbol([ssemic, send, srpar]);
(* currsym is the symbol following record end/rpar,
(usually semicolon, sometimes enclosing end/rpar) *)
precord := tp
end;
function ptypedef;
var tp,
tq : treeptr;
st : symtyp;
ss : symset;
begin
nextsymbol([sid, slpar, sarrow, sinteger, schar, splus, sminus,
spacked, sarray, srecord, sfile, sset]);
(* the "packed" keyword is completely ignored *)
if currsym.st = spacked then
nextsymbol([sarray, srecord, sfile, sset]);
ss := [ssemic, send, srpar, scomma, srbrack];
case currsym.st of
splus,
sminus,
schar,
sinteger,
sid:
begin
st := currsym.st;
tp := pconstant(false);
if st = sid then
nextsymbol([sdotdot] + ss)
else
nextsymbol([sdotdot]);
if currsym.st = sdotdot then
begin
nextsymbol([sid, sinteger, schar,
splus, sminus]);
tq := mknode(nsubrange);
tq^.tlo := tp;
tq^.thi := pconstant(false);
tp := tq;
nextsymbol(ss)
end
end;
slpar:
begin
tp := mknode(nscalar);
nextsymbol([sid]);
tp^.tscalid := pidlist(lidentifier);
checksymbol([srpar]);
nextsymbol(ss)
end;
sarrow:
begin
tp := mknode(nptr);
nextsymbol([sid]);
tp^.tptrid := oldid(currsym.vid, lpointer);
tp^.tptrflag := false;
nextsymbol([ssemic, send, srpar])
end;
sarray:
begin
nextsymbol([slbrack]);
tp := mknode(narray);
tp^.taindx := ptypedef; (* parse subrange ... *)
tq := tp;
while currsym.st = scomma do
begin
(* expand: array [ A , B ] of X
to: array [ A ] of array [ B ] of X *)
tq^.taelem := mknode(narray);
tq := tq^.taelem;
tq^.taindx := ptypedef (* ... again *)
end;
checksymbol([srbrack]);
nextsymbol([sof]);
tq^.taelem := ptypedef
end;
srecord:
tp := precord(send, nil);
sfile,
sset:
begin
if currsym.st = sfile then
tp := mknode(nfileof)
else begin
tp := mknode(nsetof);
usesets := true
end;
nextsymbol([sof]);
tp^.tof := ptypedef
end
end;
(* at this point "currsym" holds the symbol following the type
(usually semicolon, sometimes the following end/rpar) *)
ptypedef := tp
end;
(* Parse type-clause. *)
function ptype;
var tp,
tq : treeptr;
begin
tq := nil;
nextsymbol([sid]);
repeat
if tq = nil then
begin
tq := mknode(ntype);
tq^.tattr := anone;
tp := tq
end
else begin
tq^.tnext := mknode(ntype);
tq := tq^.tnext;
tq^.tattr := anone
end;
tq^.tidl := pidlist(lidentifier);
checksymbol([seq]);
tq^.tbind := ptypedef;
nextsymbol([sid, svar, sbegin, sfunc, sproc, seof])
until currsym.st <> sid;
ptype := tp;
end;
(* Parse var-clause. *)
function pvar;
var ti,
tp,
tq : treeptr;
begin
tq := nil;
nextsymbol([sid]);
repeat
if tq = nil then
begin
tq := mknode(nvar);
tq^.tattr := anone;
tp := tq
end
else begin
tq^.tnext := mknode(nvar);
tq := tq^.tnext;
tq^.tattr := anone
end;
ti := newid(currsym.vid);
tq^.tidl := ti;
nextsymbol([scomma, scolon]);
while currsym.st = scomma do
begin
nextsymbol([sid]);
ti^.tnext := newid(currsym.vid);
ti := ti^.tnext;
nextsymbol([scomma, scolon])
end;
tq^.tbind := ptypedef;
nextsymbol([sid, sbegin, sfunc, sproc, seof])
until currsym.st <> sid;
pvar := tp
end;
(* Parse subroutine-declaration. *)
function psubs;
var tp, (* return value *)
tv, tq : treeptr; (* temporary *)
func : boolean; (* true for functions *)
colsem : symtyp; (* colon/semicolon *)
begin
(* parsing function or procedure *)
func := currsym.st = sfunc;
if func then
colsem := scolon
else
colsem := ssemic;
(* parse id, it may already be forward declared *)
nextsymbol([sid]);
tq := newid(currsym.vid);
if tq^.tup = nil then
begin
enterscope(nil);
(* id wasn't previously declared, params possible *)
if func then
tp := mknode(nfunc)
else
tp := mknode(nproc);
tp^.tstat := statlvl;
tp^.tsubid := tq;
linkup(tp, tq);
nextsymbol([slpar, colsem]);
if currsym.st = slpar then
begin
tp^.tsubpar := psubpar;
linkup(tp, tp^.tsubpar);
nextsymbol([colsem])
end
else
tp^.tsubpar := nil;
if func then
begin
(* parse function type *)
nextsymbol([sid]);
tp^.tfuntyp := oldid(currsym.vid, lidentifier);
nextsymbol([ssemic])
end
else
tp^.tfuntyp := mknode(nempty);
linkup(tp, tp^.tfuntyp);
nextsymbol([sextern, sforward,
slabel, sconst, stype, svar,
sproc, sfunc, sbegin]);
end
else begin
(* id was forward declared =>
pick up declarations from parameterlist *)
enterscope(tq^.tup^.tscope);
if func then
tp := mknode(nfunc)
else
tp := mknode(nproc);
tp^.tfuntyp := tq^.tup^.tfuntyp;
(* steal id and params from forward decl *)
tv := tq^.tup^.tsubpar;
tp^.tsubpar := tv;
while tv <> nil do
begin
tv^.tup := tp;
tv := tv^.tnext
end;
tp^.tsubid := tq;
tq^.tup := tp;
(* id was forward declared =>
no params, no function type, no forward *)
nextsymbol([ssemic]);
nextsymbol([slabel, sconst, stype, svar,
sproc, sfunc, sbegin]);
end;
if currsym.st in [sforward, sextern] then
begin
tp^.tsubid^.tsym^.lt := lforward;
nextsymbol([ssemic]);
tp^.tsublab := nil;
tp^.tsubconst := nil;
tp^.tsubtype := nil;
tp^.tsubvar := nil;
tp^.tsubsub := nil;
tp^.tsubstmt := nil
end
else
pbody(tp);
nextsymbol([sproc, sfunc, sbegin, seof]);
tp^.tscope := currscope;
leavescope;
psubs := tp
end;
(* Parse a conformant array index type. *)
function pconfsub : treeptr;
var tp : treeptr;
begin
tp := mknode(nsubrange);
nextsymbol([sid]);
tp^.tlo := newid(currsym.vid);
nextsymbol([sdotdot]);
nextsymbol([sid]);
tp^.thi := newid(currsym.vid);
nextsymbol([scolon]);
pconfsub := tp
end;
(* Parse a conformant array-declaration. *)
function pconform : treeptr;
var tp, tq : treeptr;
begin
nextsymbol([slbrack]);
tp := mknode(nconfarr);
tp^.tcuid := mkvariable('S');
tp^.tcindx := pconfsub; (* parse subrange ... *)
nextsymbol([sid]);
tp^.tindtyp := oldid(currsym.vid, lidentifier);
nextsymbol([ssemic, srbrack]);
tq := tp;
while currsym.st = ssemic do
begin
error(econfconf); (* what size does tp have *)
(* expand: array [ A ; B ] of X
to: array [ A ] of array [ B ] of X *)
tq^.tcelem := mknode(nconfarr);
tq := tq^.tcelem;
tq^.tcindx := pconfsub; (* ... again *)
nextsymbol([sid]);
tq^.tindtyp := oldid(currsym.vid, lidentifier);
nextsymbol([ssemic, srbrack])
end;
nextsymbol([sof]);
nextsymbol([sid, sarray]);
case currsym.st of
sid:
tq^.tcelem := oldid(currsym.vid, lidentifier);
sarray:
begin
error(econfconf); (* what size does tp have *)
tq^.tcelem := pconform
end;
end;(* case *)
pconform := tp
end;
(* Parse subroutine parameter list. *)
function psubpar;
var tp,
tq : treeptr;
nt : treetyp;
begin
tq := nil;
repeat
nextsymbol([sid, svar, sfunc, sproc]);
case currsym.st of
sid:
nt := nvalpar;
svar:
nt := nvarpar;
sfunc:
nt := nparfunc;
sproc:
nt := nparproc;
end;
if nt <> nvalpar then
nextsymbol([sid]);
if tq = nil then
begin
tq := mknode(nt);
tp := tq
end
else begin
tq^.tnext := mknode(nt);
tq := tq^.tnext
end;
case nt of
nvarpar,
nvalpar:
begin
tq^.tidl := pidlist(lidentifier);
tq^.tattr := anone;
checksymbol([scolon]);
if nt = nvalpar then
nextsymbol([sid])
else
nextsymbol([sid, sarray]);
case currsym.st of
sid:
tq^.tbind :=
oldid(currsym.vid, lidentifier);
sarray:
tq^.tbind := pconform
end;(* case *)
nextsymbol([srpar, ssemic])
end;
nparproc:
begin
tq^.tparid := newid(currsym.vid);
nextsymbol([ssemic, slpar, srpar]);
if currsym.st = slpar then
begin
enterscope(nil);
tq^.tparparm := psubpar;
nextsymbol([ssemic, srpar]);
leavescope
end
else
tq^.tparparm := nil;
tq^.tpartyp := nil
end;
nparfunc:
begin
tq^.tparid := newid(currsym.vid);
nextsymbol([scolon, slpar]);
if currsym.st = slpar then
begin
enterscope(nil);
tq^.tparparm := psubpar;
nextsymbol([scolon]);
leavescope
end
else
tq^.tparparm := nil;
nextsymbol([sid]);
tq^.tpartyp := oldid(currsym.vid, lidentifier);
nextsymbol([srpar, ssemic])
end
end (* case *)
until currsym.st = srpar;
psubpar := tp
end;
(* Parse a (possibly labeled) statement. *)
function plabstmt;
var tp : treeptr;
begin
nextsymbol([sid, sinteger, sif, swhile, srepeat, sfor, scase,
swith, sbegin, sgoto,
selse, ssemic, send, suntil]);
if currsym.st = sinteger then
begin
tp := mknode(nlabstmt);
tp^.tlabno := oldlbl(true);
nextsymbol([scolon]);
nextsymbol([sid, sif, swhile, srepeat, sfor, scase,
swith, sbegin, sgoto,
selse, ssemic, send, suntil]);
tp^.tstmt := pstmt
end
else
tp := pstmt;
plabstmt := tp
end;
(* Parse an unlabeled statement. *)
function pstmt;
var tp : treeptr;
begin
case currsym.st of
sid:
tp := psimple;
sif:
tp := pif;
swhile:
tp := pwhile;
srepeat:
tp := prepeat;
sfor:
tp := pfor;
scase:
tp := pcase;
swith:
tp := pwith;
sbegin:
tp := pbegin(true);
sgoto:
tp := pgoto;
send,
selse,
suntil,
ssemic:
tp := mknode(nempty);
end;
pstmt := tp
end;
(* Parse an assignment or a procedure call. *)
function psimple;
var tq,
tp : treeptr;
begin
tp := pvariable(oldid(currsym.vid, lidentifier));
if currsym.st = sassign then
begin
tq := mknode(nassign);
tq^.tlhs := tp;
tq^.trhs := pexpr(nil);
tp := tq
end;
psimple := tp
end;
(* Parse a varable-reference (or a subroutine-call). *)
function pvariable;
var tp,
tq : treeptr;
begin
nextsymbol([slpar, slbrack, sdot, sarrow,
sassign, ssemic, scomma, scolon, sdotdot,
splus, sminus, smul, sdiv, smod, squot,
sand, sor, sinn, srpar, srbrack,
sle, slt, seq, sge, sgt, sne,
send, suntil, sthen, selse, sdo, sdownto, sto, sof]);
if currsym.st in [slpar, slbrack, sdot, sarrow] then
begin
case currsym.st of
slpar:
begin
tp := mknode(ncall);
tp^.tcall := varptr;
tq := nil;
repeat
if tq = nil then
begin
tq := pexpr(nil);
tp^.taparm := tq
end
else begin
tq^.tnext := pexpr(nil);
tq := tq^.tnext
end;
until currsym.st = srpar
end;
slbrack:
begin
tq := varptr;
repeat
tp := mknode(nindex);
tp^.tvariable := tq;
tp^.toffset := pexpr(nil);
tq := tp
until currsym.st = srbrack
end;
sdot:
begin
tp := mknode(nselect);
tp^.trecord := varptr;
nextsymbol([sid]);
tq := typeof(varptr);
enterscope(tq^.trscope);
tp^.tfield := oldid(currsym.vid, lfield);
leavescope
end;
sarrow:
begin
tp := mknode(nderef);
tp^.texps := varptr
end
end;(* case *)
tp := pvariable(tp)
end
else begin
tp := varptr;
if tp^.tt = nid then
begin
tq := idup(tp);
if tq <> nil then
if tq^.tt in [nfunc, nproc,
nparproc, nparfunc] then
begin
(* subroutine-call without
parameters *)
tp := mknode(ncall);
tp^.tcall := varptr;
tp^.taparm := nil
end
end
end;
pvariable := tp
end;
(* Parse an expression. *)
function pexpr;
var tp,
tq : treeptr;
nt : treetyp;
next : boolean;
function padjust(tu, tr : treeptr) : treeptr;
begin
if pprio[tu^.tt] >= pprio[tr^.tt] then
begin
if tr^.tt in [nnot, numinus, nuplus,
nset, nderef] then
tr^.texps := padjust(tu, tr^.texps)
else
tr^.texpl := padjust(tu, tr^.texpl);
padjust := tr
end
else begin
if tu^.tt in [nnot, numinus, nuplus,
nset, nderef] then
tu^.texps := tr
else
tu^.texpr := tr;
padjust := tu
end
end;
begin
nextsymbol([sid, schar, sinteger, sreal, sstring, snil,
splus, sminus, snot, slpar, slbrack, srbrack]);
next := true;
case currsym.st of
splus:
begin
tp := mknode(nuplus);
tp^.texps := nil;
tp := pexpr(tp);
next := false
end;
sminus:
begin
tp := mknode(numinus);
tp^.texps := nil;
tp := pexpr(tp);
next := false
end;
snot:
begin
tp := mknode(nnot);
tp^.texps := nil;
tp := pexpr(tp);
next := false
end;
schar,
sinteger,
sreal,
sstring:
tp := mklit;
snil:
begin
usenilp := true;
tp := mknode(nnil);
end;
sid:
begin
tp := pvariable(oldid(currsym.vid, lidentifier));
next := false
end;
slpar:
begin
tp := mknode(nuplus);
tp^.texps := pexpr(nil)
end;
slbrack:
begin
usesets := true;
tp := mknode(nset);
tp^.texps := nil;
tq := nil;
repeat
if tq = nil then
begin
tq := pexpr(nil);
tp^.texps := tq
end
else begin
tq^.tnext := pexpr(nil);
tq := tq^.tnext
end
until currsym.st = srbrack;
end;
srbrack:
begin
tp := mknode(nempty);
next := false
end
end;
if next then
nextsymbol([
scolon, ssemic, scomma, sdotdot, srpar, srbrack,
sle, slt, seq, sge, sgt, sne,
splus, sminus, smul, sdiv, smod, squot,
sand, sor, sinn,
send, suntil, sthen, selse, sdo, sdownto, sto,
sof, slpar, slbrack]);
case currsym.st of
sdotdot:
nt := nrange;
splus:
nt := nplus;
sminus:
nt := nminus;
smul:
nt := nmul;
sdiv:
nt := ndiv;
smod:
nt := nmod;
squot:
begin
defnams[dreal]^.lused := true;
nt := nquot;
end;
sand:
nt := nand;
sor:
nt := nor;
sinn:
begin
nt := nin;
usesets := true
end;
sle:
nt := nle;
slt:
nt := nlt;
seq:
nt := neq;
sge:
nt := nge;
sgt:
nt := ngt;
sne:
nt := nne;
scolon:
nt := nformat;
sid, schar, sinteger, sreal, sstring, snil,
ssemic, scomma, slpar, slbrack, srpar, srbrack,
send, suntil, sthen, selse, sdo, sdownto, sto, sof:
nt := nnil
end;(* case *)
if nt in [nin .. nor, nand, nnot] then
defnams[dboolean]^.lused := true;
if nt <> nnil then
begin
(* binary operator *)
tq := mknode(nt);
tq^.texpl := tp;
tq^.texpr := nil;
tp := pexpr(tq)
end;
(* this statement yilds proper operator precedence *)
if tnp <> nil then
tp := padjust(tnp, tp);
pexpr := tp
end;
(* Parse a case-statement. *)
function pcase;
label 999;
var tp,
tq,
tv : treeptr;
begin
tp := mknode(ncase);
tp^.tcasxp := pexpr(nil);
checksymbol([sof]);
tq := nil;
repeat
if tq = nil then
begin
tq := mknode(nchoise);
tp^.tcaslst := tq
end
else begin
tq^.tnext := mknode(nchoise);
tq := tq^.tnext
end;
tv := nil;
repeat
nextsymbol([sid, sinteger, schar,
splus, sminus, send, sother]);
if currsym.st in [send, sother] then
goto 999;
if tv = nil then
begin
tv := pconstant(false);
tq^.tchocon := tv
end
else begin
tv^.tnext := pconstant(false);
tv := tv^.tnext
end;
nextsymbol([scomma, scolon])
until currsym.st = scolon;
tq^.tchostmt := plabstmt
until currsym.st = send;
999:
if currsym.st = sother then
begin
nextsymbol([scolon, sid, sif, swhile, srepeat, sfor,
scase, swith, sbegin, sgoto,
selse, ssemic, send, suntil]);
if currsym.st = scolon then
nextsymbol([sid, sif, swhile, srepeat, sfor,
scase, swith, sbegin, sgoto,
selse, ssemic, send, suntil]);
tp^.tcasother := pstmt
end
else begin
tp^.tcasother := nil;
usecase := true
end;
nextsymbol([ssemic, send, selse, suntil]);
pcase := tp
end;
(* Parse an if-statement. *)
function pif;
var tp : treeptr;
begin
tp := mknode(nif);
tp^.tifxp := pexpr(nil);
checksymbol([sthen]);
tp^.tthen := plabstmt;
if currsym.st = selse then
tp^.telse := plabstmt
else
tp^.telse := nil;
pif := tp;
end;
(* Parse a while-statement. *)
function pwhile;
var tp : treeptr;
begin
tp := mknode(nwhile);
tp^.twhixp := pexpr(nil);
checksymbol([sdo]);
tp^.twhistmt := plabstmt;
pwhile := tp;
end;
(* Parse a repeat-statement. *)
function prepeat;
var tp,
tq : treeptr;
begin
tp := mknode(nrepeat);
tq := nil;
repeat
if tq = nil then
begin
tq := plabstmt;
tp^.treptstmt := tq
end
else begin
tq^.tnext := plabstmt;
tq := tq^.tnext
end;
checksymbol([ssemic, suntil])
until currsym.st = suntil;
tp^.treptxp := pexpr(nil);
prepeat := tp
end;
(* Parse a for-statement. *)
function pfor;
var tp : treeptr;
begin
tp := mknode(nfor);
nextsymbol([sid]);
tp^.tforid := oldid(currsym.vid, lidentifier);
nextsymbol([sassign]);
tp^.tfrom := pexpr(nil);
checksymbol([sdownto, sto]);
tp^.tincr := currsym.st = sto;
tp^.tto := pexpr(nil);
checksymbol([sdo]);
tp^.tforstmt := plabstmt;
pfor := tp
end;
(* Parse a with-statement. *)
function pwith;
var tp,
tq : treeptr;
begin
tp := mknode(nwith);
tq := nil;
repeat
if tq = nil then
begin
tq := mknode(nwithvar);
tp^.twithvar := tq
end
else begin
tq^.tnext := mknode(nwithvar);
tq := tq^.tnext
end;
enterscope(nil);
tq^.tenv := currscope;
tq^.texpw := pexpr(nil);
scopeup(tq^.texpw);
checksymbol([scomma, sdo])
until currsym.st = sdo;
tp^.twithstmt := plabstmt;
tq := tp^.twithvar;
while tq <> nil do
begin
leavescope;
tq := tq^.tnext
end;
pwith := tp
end;
(* Parse a goto-statement. *)
function pgoto;
var tp : treeptr;
begin
nextsymbol([sinteger]);
tp := mknode(ngoto);
tp^.tlabel := oldlbl(false);
nextsymbol([ssemic, send, suntil, selse]);
pgoto := tp
end;
(* Parse a begin-statement. *)
function pbegin;
var tp,
tq : treeptr;
begin
tq := nil;
repeat
if tq = nil then
begin
tq := plabstmt;
tp := tq
end
else begin
tq^.tnext := plabstmt;
tq := tq^.tnext
end
until currsym.st = send;
if retain then
begin
tq := mknode(nbegin);
tq^.tbegin := tp;
tp := tq
end;
nextsymbol([send, selse, suntil, sdot, ssemic]);
pbegin := tp
end;
begin (* parse *)
nextsymbol([spgm, sconst, stype, svar, sproc, sfunc]);
if currsym.st = spgm then
top := pprogram
else
top := pmodule;
nextsymbol([seof]);
end; (* parse *)
(* Compute value for a node (which must be some kind of constant). *)
function cvalof(tp : treeptr) : integer;
var v : integer;
tq : treeptr;
begin
case tp^.tt of
nuplus:
cvalof := cvalof(tp^.texps);
numinus:
cvalof := - cvalof(tp^.texps);
nnot:
cvalof := 1 - cvalof(tp^.texps);
nid:
begin
tq := idup(tp);
if tq = nil then
fatal(etree);
tp := tp^.tsym^.lsymdecl;
case tq^.tt of
nscalar:
begin
v := 0;
tq := tq^.tscalid;
while tq <> nil do
if tq = tp then
tq := nil
else begin
v := v + 1;
tq := tq^.tnext
end;
cvalof := v
end;
nconst:
cvalof := cvalof(tq^.tbind);
end;(* case *)
end;
ninteger:
cvalof := tp^.tsym^.linum;
nchar:
cvalof := ord(tp^.tsym^.lchar);
end (* case *)
end; (* cvalof *)
(* Compute lower value of subrange or scalar type. *)
function clower(tp : treeptr) : integer;
var tq : treeptr;
begin
tq := typeof(tp);
if tq^.tt = nscalar then
clower := scalbase
else if tq^.tt = nsubrange then
if tq^.tup^.tt = nconfarr then
clower := 0
else
clower := cvalof(tq^.tlo)
else if tq = typnods[tchar] then
clower := 0
else if tq = typnods[tinteger] then
clower := -maxint
else
fatal(etree)
end; (* clower *)
(* Compute upper value of subrange or scalar type. *)
function cupper(tp : treeptr) : integer;
var tq : treeptr;
i : integer;
begin
tq := typeof(tp);
if tq^.tt = nscalar then
begin
tq := tq^.tscalid;
i := scalbase;
while tq^.tnext <> nil do
begin
i := i + 1;
tq := tq^.tnext
end;
cupper := i
end
else if tq^.tt = nsubrange then
if tq^.tup^.tt = nconfarr then
fatal(euprconf)
else
cupper := cvalof(tq^.thi)
else if tq = typnods[tchar] then
cupper := maxchar
else if tq = typnods[tinteger] then
cupper := maxint
else
fatal(etree)
end; (* cupper *)
(* Compute the number of elements in a subrange. *)
function crange(tp : treeptr) : integer;
begin
crange := cupper(tp) - clower(tp) + 1
end;
(* Return number of words uset to store a set. *)
function csetwords(i : integer) : integer;
begin
i := (i+(setbits)) div (setbits+1);
if i > maxsetrange then
error(esetsize);
csetwords := i
end;
(* Return number of words uset to store a set. *)
function csetsize(tp : treeptr) : integer;
var tq : treeptr;
i : integer;
begin
tq := typeof(tp^.tof);
i := clower(tq);
(* bits in sets are always numbered from 0, so we (arbitrarily)
decide that the base must be in the first 6 words to avoid
unnecessary waste of space *)
if (i < 0) or (i >= 6 * (setbits+1)) then
error(esetbase);
csetsize := csetwords(crange(tq)) + 1
end;
(* Determine if tp is declared in the procedure it is used in. *)
function islocal(tp : treeptr) : boolean;
var tq : treeptr;
begin
tq := tp^.tsym^.lsymdecl;
while not (tq^.tt in [nproc, nfunc, npgm]) do
tq := tq^.tup;
while not (tp^.tt in [nproc, nfunc, npgm]) do
tp := tp^.tup;
islocal := tp = tq
end;
(* Perform necessary transformations on tree and identifiers *)
(* before generating code. *)
procedure transform;
(* Rename function when used as a variable. *)
procedure renamf(tp : treeptr);
var ip, iq : symptr;
tq, tv : treeptr;
(* This procedure recursively descends the tree *)
(* and replaces function-assignments with variable *)
(* assignments. *)
procedure crtnvar(tp : treeptr);
begin
while tp <> nil do
begin
case tp^.tt of
npgm:
crtnvar(tp^.tsubsub);
nfunc,
nproc:
begin
crtnvar(tp^.tsubsub);
crtnvar(tp^.tsubstmt)
end;
nbegin:
crtnvar(tp^.tbegin);
nif:
begin
crtnvar(tp^.tthen);
crtnvar(tp^.telse)
end;
nwhile:
crtnvar(tp^.twhistmt);
nrepeat:
crtnvar(tp^.treptstmt);
nfor:
crtnvar(tp^.tforstmt);
ncase:
begin
crtnvar(tp^.tcaslst);
crtnvar(tp^.tcasother)
end;
nchoise:
crtnvar(tp^.tchostmt);
nwith:
crtnvar(tp^.twithstmt);
nlabstmt:
crtnvar(tp^.tstmt);
nassign:
begin
(* revoke calls in assignment lhs, (mis-
parsed due to ambiguous syntax) *)
if tp^.tlhs^.tt = ncall then
begin
tp^.tlhs := tp^.tlhs^.tcall;
tp^.tlhs^.tup := tp
end;
(* function name -> variable name *)
tv := tp^.tlhs;
if tv^.tt = nid then
if tv^.tsym = ip then
tv^.tsym := iq
end;
nbreak,
npush,
npop,
ngoto,
nempty,
ncall:
(* no op *)
end;(* case *)
tp := tp^.tnext
end
end;
begin (* renamf *)
while tp <> nil do
begin
case tp^.tt of
npgm,
nproc:
renamf(tp^.tsubsub);
nfunc:
begin
(* create a variable to hold return value *)
tq := mknode(nvar);
tq^.tattr := aregister;
tq^.tup := tp;
tq^.tidl := newid(mkvariable('R'));
tq^.tidl^.tup := tq;
tq^.tbind := tp^.tfuntyp;
(* put it FIRST among variables, see esubr() *)
tq^.tnext := tp^.tsubvar;
tp^.tsubvar := tq;
iq := tq^.tidl^.tsym;
ip := tp^.tsubid^.tsym;
crtnvar(tp^.tsubsub);
crtnvar(tp^.tsubstmt);
(* process inner functions *)
renamf(tp^.tsubsub)
end;
end;(* case *)
tp := tp^.tnext
end
end; (* renamf *)
(* This procedure rearranges the tree such that multiple *)
(* vardeclarations don't have (structured) types attached *)
(* to them. If such a declararation is found, a new name *)
(* is created and the type is moved to the type section. *)
procedure extract(tp : treeptr);
var vp : treeptr;
(* Create a declaration for tp, enter in pp type- *)
(* list and return an identifier referencing it. *)
function xtrit(tp, pp : treeptr; last : boolean) : treeptr;
var np, rp : treeptr;
ip : idptr;
begin
(* create new declaration *)
np := mknode(ntype);
ip := mkvariable('T');
np^.tidl := newid(ip);
np^.tidl^.tup := np;
(* create substitute id *)
rp := oldid(ip, lidentifier);
rp^.tup := tp^.tup;
rp^.tnext := tp^.tnext;
(* steal type description *)
np^.tbind := tp;
tp^.tup := np;
tp^.tnext := nil;
(* add new declaration to tree *)
np^.tup := pp;
if last and (pp^.tsubtype <> nil) then
begin
pp := pp^.tsubtype;
while pp^.tnext <> nil do
pp := pp^.tnext;
pp^.tnext := np
end
else begin
np^.tnext := pp^.tsubtype;
pp^.tsubtype := np;
end;
xtrit := rp;
end;
(* Extract anonymous enumeration types. *)
function xtrenum(tp, pp : treeptr) : treeptr;
(* Name record-types referenced by ptrs. *)
procedure nametype(tp : treeptr);
begin
tp := typeof(tp);
if tp^.tt = nrecord then
if tp^.tuid = nil then
tp^.tuid := mkvariable('S');
end;
begin
if tp <> nil then
begin
case tp^.tt of
nfield,
ntype,
nvar:
tp^.tbind :=
xtrenum(tp^.tbind, pp);
nscalar:
if tp^.tup^.tt <> ntype then
tp := xtrit(tp, pp, false);
narray:
begin
tp^.taindx := xtrenum(tp^.taindx, pp);
tp^.taelem := xtrenum(tp^.taelem, pp);
end;
nrecord:
begin
tp^.tflist := xtrenum(tp^.tflist, pp);
tp^.tvlist := xtrenum(tp^.tvlist, pp);
end;
nvariant:
tp^.tvrnt := xtrenum(tp^.tvrnt, pp);
nfileof:
tp^.tof := xtrenum(tp^.tof, pp);
nptr:
nametype(tp^.tptrid);
nid,
nsubrange,
npredef,
nempty,
nsetof:
(* no op *)
end;(* case *)
tp^.tnext := xtrenum(tp^.tnext, pp)
end;
xtrenum := tp
end;
begin (* extract *)
while tp <> nil do
begin
(* tp points to a program/procedure/function node *)
tp^.tsubtype := xtrenum(tp^.tsubtype, tp);
tp^.tsubvar := xtrenum(tp^.tsubvar, tp);
vp := tp^.tsubvar;
while vp <> nil do
begin
(* variables of structured unnamed types *)
if vp^.tbind^.tt in [nscalar, narray,
nrecord, nfileof] then
vp^.tbind := xtrit(vp^.tbind, tp, true);
vp := vp^.tnext
end;
extract(tp^.tsubsub);
tp := tp^.tnext
end
end; (* extract *)
(* This procedure moves all local constants and types *)
(* used in nested procedures to the outermost declaration *)
(* level so that nested procedures may be extracted. *)
procedure global(tp, dp : treeptr; depend : boolean);
label 555;
var ip : treeptr;
dep : boolean;
(* Mark all declared identifiers as unused. *)
procedure markdecl(xp : treeptr);
begin
while xp <> nil do
begin
case xp^.tt of
nid:
xp^.tsym^.lused := false;
nconst:
markdecl(xp^.tidl);
ntype,
nvar,
nvalpar,
nvarpar,
nfield:
begin
markdecl(xp^.tidl);
if xp^.tbind^.tt <> nid then
markdecl(xp^.tbind)
end;
nscalar:
markdecl(xp^.tscalid);
nrecord:
begin
markdecl(xp^.tflist);
markdecl(xp^.tvlist)
end;
nvariant:
markdecl(xp^.tvrnt);
nconfarr:
if xp^.tcelem^.tt <> nid then
markdecl(xp^.tcelem);
narray:
if xp^.taelem^.tt <> nid then
markdecl(xp^.taelem);
nsetof,
nfileof:
if xp^.tof^.tt <> nid then
markdecl(xp^.tof);
nparproc,
nparfunc:
markdecl(xp^.tparid);
nptr,
nsubrange:
(* no op *)
end;(* case *)
xp := xp^.tnext
end
end; (* markdecl *)
(* Move all marked declarations to global scope. *)
function movedecl(tp : treeptr) : treeptr;
var ip, np : treeptr;
sp : symptr;
move : boolean;
begin
if tp <> nil then
begin
move := false;
case tp^.tt of
nconst,
ntype:
ip := tp^.tidl
end;(* case *)
while ip <> nil do
begin
if ip^.tsym^.lused then
begin
move := true;
sp := ip^.tsym;
if sp^.lid^.inref > 1 then
begin
sp^.lid :=
mkrename( 'M', sp^.lid);
sp^.lid^.inref :=
sp^.lid^.inref - 1
end;
ip := nil
end
else
ip := ip^.tnext
end;
if move then
begin
np := tp^.tnext;
tp^.tnext := nil;
ip := tp;
while ip^.tt <> npgm do
ip := ip^.tup;
tp^.tup := ip;
case tp^.tt of
nconst:
begin
if ip^.tsubconst = nil then
ip^.tsubconst := tp
else begin
ip := ip^.tsubconst;
while ip^.tnext <> nil
do ip := ip^.tnext;
ip^.tnext := tp
end
end;
ntype:
begin
if ip^.tsubtype = nil then
ip^.tsubtype := tp
else begin
ip := ip^.tsubtype;
while ip^.tnext <> nil
do ip := ip^.tnext;
ip^.tnext := tp
end
end
end;(* case *)
(* tp is moved, drop it and process
remainder of declarationlist *)
tp := movedecl(np)
end
else
tp^.tnext := movedecl(tp^.tnext)
end;
movedecl := tp
end; (* movedecl *)
(* This procedure lifts out variables/parameters *)
(* used in nested procedures/functions. *)
procedure movevars(tp, vp : treeptr);
label 555;
var ep, dp, np : treeptr;
ip : idptr;
sp : symptr;
(* Move a variable declaration to global *)
(* var declaration lists. *)
procedure moveglob(tp, dp : treeptr);
begin
while tp^.tt <> npgm do
tp := tp^.tup;
dp^.tup := tp;
dp^.tnext := tp^.tsubvar;
tp^.tsubvar := dp
end;
(* Create nodes for saving a global *)
(* pointer variable. *)
function stackop(decl, glob, loc : treeptr) : treeptr;
var op, ip, dp, tp : treeptr;
begin
(* create a new variable to hold old value
of the global variable during a call *)
ip := newid(mkvariable('F'));
case vp^.tt of
nvarpar,
nvalpar,
nvar:
begin
dp := mknode(nvarpar);
dp^.tattr := areference;
dp^.tidl := ip;
(* use same type as the global var *)
dp^.tbind := decl^.tbind
end;
nparproc,
nparfunc:
begin
dp := mknode(vp^.tt);
dp^.tparid := ip;
dp^.tparparm := nil;
dp^.tpartyp := vp^.tpartyp
end
end;(* case *)
ip^.tup := dp;
(* add variable to declarationlists *)
tp := decl;
while not (tp^.tt in [nproc, nfunc, npgm]) do
tp := tp^.tup;
dp^.tup := tp;
if tp^.tsubvar = nil then
tp^.tsubvar := dp
else begin
tp := tp^.tsubvar;
while tp^.tnext <> nil do
tp := tp^.tnext;
tp^.tnext := dp
end;
dp^.tnext := nil;
(* create an assignment saving value *)
op := mknode(npush);
op^.tglob := glob;
op^.tloc := loc;
op^.ttmp := ip;
stackop := op
end;
(* Take a "push" node, create "pop" node *)
(* and add both to tree. *)
procedure addcode(tp, push : treeptr);
var pop : treeptr;
begin
pop := mknode(npop);
(* share variables with "push"-node *)
pop^.tglob := push^.tglob;
pop^.ttmp := push^.ttmp;
pop^.tloc := nil;
(* add npush to head of statement list *)
push^.tnext := tp^.tsubstmt;
tp^.tsubstmt := push;
push^.tup := tp;
(* add npop to end of statement list *)
while push^.tnext <> nil do
push := push^.tnext;
push^.tnext := pop;
pop^.tup := tp
end;
begin (* movevars *)
while vp <> nil do
begin
case vp^.tt of
nvar,
nvalpar,
nvarpar:
dp := vp^.tidl;
nparproc,
nparfunc:
begin
dp := vp^.tparid;
if dp^.tsym^.lused then
begin
(* create a var declaration *)
ep := mknode(vp^.tt);
ep^.tparparm := nil;
ep^.tpartyp := vp^.tpartyp;
np := newid(mkrename('G',
dp^.tsym^.lid));
ep^.tparid := np;
np^.tup := ep;
(* swap id's and symbols *)
sp := np^.tsym;
ip := sp^.lid;
np^.tsym^.lid := dp^.tsym^.lid;
dp^.tsym^.lid := ip;
np^.tsym := dp^.tsym;
dp^.tsym := sp;
np^.tsym^.lsymdecl := np;
dp^.tsym^.lsymdecl := dp;
(* make declaration global *)
moveglob(tp, ep);
(* add save/restore-code *)
addcode(tp, stackop(vp, np, dp))
end;
goto 555
end
end;(* case *)
while dp <> nil do
begin
if dp^.tsym^.lused then
begin
(* create a varpar declaration,
(nvarpar will cause emit to
treat the new identifier
as a pointer) *)
ep := mknode(nvarpar);
ep^.tattr := areference;
np := newid(mkrename('G',
dp^.tsym^.lid));
ep^.tidl := np;
np^.tup := ep;
ep^.tbind := vp^.tbind;
if ep^.tbind^.tt = nid then
ep^.tbind^.tsym^.lused
:= true;
(* swap id's and symbols *)
sp := np^.tsym;
ip := sp^.lid;
np^.tsym^.lid := dp^.tsym^.lid;
dp^.tsym^.lid := ip;
np^.tsym := dp^.tsym;
dp^.tsym := sp;
np^.tsym^.lsymdecl := np;
dp^.tsym^.lsymdecl := dp;
(* note that dp is referenced *)
dp^.tup^.tattr := aextern;
(* make declaration global *)
moveglob(tp, ep);
(* add save/restore-code *)
addcode(tp, stackop(vp, np, dp))
end;
dp := dp^.tnext
end;
555:
vp := vp^.tnext
end
end; (* movevars *)
(* Break out a local variable and set the register *)
(* attribute. *)
procedure registervar(tp : treeptr);
var vp, xp : treeptr;
begin
vp := idup(tp);
tp := tp^.tsym^.lsymdecl;
(* vp points to nvar node *)
if (vp^.tidl <> tp) or (tp^.tnext <> nil) then
begin
(* tp is not alone in list of identifiers,
create a new nvar-node and hook up tp *)
xp := mknode(nvar);
xp^.tattr := anone;
xp^.tidl := tp;
tp^.tup := xp;
(* enter new nvar node among declarations *)
xp^.tup := vp^.tup;
xp^.tbind := vp^.tbind; (* borrow type *)
xp^.tnext := vp^.tnext;
vp^.tnext := xp;
(* break tp out of list of identifiers *)
if vp^.tidl = tp then
vp^.tidl := tp^.tnext
else begin
vp := vp^.tidl;
while vp^.tnext <> tp do
vp := vp^.tnext;
vp^.tnext := tp^.tnext
end;
tp^.tnext := nil
end;
(* tp is alone in this declaration, set attribute *)
if tp^.tup^.tattr = anone then
tp^.tup^.tattr := aregister
end; (* registervar *)
(* Check static declarationlevel for a label *)
(* used in a non-local goto. *)
procedure cklevel(tp : treeptr);
begin
tp := tp^.tsym^.lsymdecl;
while not(tp^.tt in [npgm, nproc, nfunc]) do
tp := tp^.tup;
if tp^.tstat > maxlevel then
maxlevel := tp^.tstat
end;
begin (* global *)
while tp <> nil do
begin
case tp^.tt of
nproc,
nfunc:
begin
(* procid/parameters/const/type/var not used *)
markdecl(tp^.tsubid);
markdecl(tp^.tsubpar);
markdecl(tp^.tsubconst);
markdecl(tp^.tsubtype);
markdecl(tp^.tsubvar);
(* mark those used in nested subroutines *)
global(tp^.tsubsub, tp, false);
(* move out variables used in inner scope *)
movevars(tp, tp^.tsubpar);
movevars(tp, tp^.tsubvar);
(* move out const/type used in inner scope *)
tp^.tsubtype := movedecl(tp^.tsubtype);
tp^.tsubconst := movedecl(tp^.tsubconst);
(* mark identifiers used in this subroutine *)
global(tp^.tsubstmt, tp, true);
global(tp^.tsubpar, tp, false);
global(tp^.tsubvar, tp, false);
global(tp^.tsubtype, tp, false);
global(tp^.tfuntyp, tp, false);
end;
npgm:
begin
markdecl(tp^.tsubconst);
markdecl(tp^.tsubtype);
markdecl(tp^.tsubvar);
global(tp^.tsubsub, tp, false);
global(tp^.tsubstmt, tp, true)
end;
nconst,
ntype,
nvar,
nfield,
nvalpar,
nvarpar:
begin
ip := tp^.tidl;
dep := depend;
while (ip <> nil) and not dep do
begin
(* for all used identifiers, propagate
the use to their bindings *)
if ip^.tsym^.lused then
dep := true;
ip := ip^.tnext
end;
global(tp^.tbind, dp, dep);
end;
nparproc,
nparfunc:
begin
global(tp^.tparparm, dp, depend);
global(tp^.tpartyp, dp, depend)
end;
nsubrange:
begin
global(tp^.tlo, dp, depend);
global(tp^.thi, dp, depend)
end;
nvariant:
begin
global(tp^.tselct, dp, depend);
global(tp^.tvrnt, dp, depend)
end;
nrecord:
begin
global(tp^.tflist, dp, depend);
global(tp^.tvlist, dp, depend)
end;
nconfarr:
begin
global(tp^.tcindx, dp, depend);
global(tp^.tcelem, dp, depend)
end;
narray:
begin
global(tp^.taindx, dp, depend);
global(tp^.taelem, dp, depend)
end;
nfileof,
nsetof:
global(tp^.tof, dp, depend);
nptr:
global(tp^.tptrid, dp, depend);
nscalar:
global(tp^.tscalid, dp, depend);
nbegin:
global(tp^.tbegin, dp, depend);
nif:
begin
global(tp^.tifxp, dp, depend);
global(tp^.tthen, dp, depend);
global(tp^.telse, dp, depend)
end;
nwhile:
begin
global(tp^.twhixp, dp, depend);
global(tp^.twhistmt, dp, depend)
end;
nrepeat:
begin
global(tp^.treptstmt, dp, depend);
global(tp^.treptxp, dp, depend)
end;
nfor:
begin
ip := idup(tp^.tforid);
if ip^.tup^.tt in [nproc, nfunc] then
registervar(tp^.tforid);
global(tp^.tforid, dp, depend);
global(tp^.tfrom, dp, depend);
global(tp^.tto, dp, depend);
global(tp^.tforstmt, dp, depend)
end;
ncase:
begin
global(tp^.tcasxp, dp, depend);
global(tp^.tcaslst, dp, depend);
global(tp^.tcasother, dp, depend)
end;
nchoise:
begin
global(tp^.tchocon, dp, depend);
global(tp^.tchostmt, dp, depend);
end;
nwith:
begin
global(tp^.twithvar, dp, depend);
global(tp^.twithstmt, dp, depend)
end;
nwithvar:
begin
ip := typeof(tp^.texpw);
if ip^.tuid = nil then
ip^.tuid := mkvariable('S');
global(tp^.texpw, dp, depend);
end;
nlabstmt:
global(tp^.tstmt, dp, depend);
neq, nne, nlt, nle, ngt, nge:
begin
global(tp^.texpl, dp, depend);
global(tp^.texpr, dp, depend);
ip := typeof(tp^.texpl);
if (ip = typnods[tstring]) or
(ip^.tt = narray) then
usecomp := true;
ip := typeof(tp^.texpr);
if (ip = typnods[tstring]) or
(ip^.tt = narray) then
usecomp := true
end;
nin, nor, nplus, nminus,
nand, nmul, ndiv, nmod, nquot,
nformat, nrange:
begin
global(tp^.texpl, dp, depend);
global(tp^.texpr, dp, depend)
end;
nassign:
begin
global(tp^.tlhs, dp, depend);
global(tp^.trhs, dp, depend)
end;
nnot,
numinus,
nuplus,
nderef:
global(tp^.texps, dp, depend);
nset:
global(tp^.texps, dp, depend);
nindex:
begin
global(tp^.tvariable, dp, depend);
global(tp^.toffset, dp, depend)
end;
nselect:
global(tp^.trecord, dp, depend);
ncall:
begin
global(tp^.tcall, dp, depend);
global(tp^.taparm, dp, depend)
end;
nid:
begin
(* find declaration point *)
ip := idup(tp);
if ip = nil then
goto 555;
(* ip points to nconst/ntype/nvar/nproc/nfunc/
nvalpar/nvarpar/nparproc or nparfunc node,
move to beginning of enclosing scope *)
repeat
ip := ip^.tup;
if ip = nil then
goto 555
(* stop only for locally declared items,
for global or predefined identifiers
we will have gone to label 555 *)
until ip^.tt in [npgm, nproc, nfunc];
if dp = ip then
begin
(* identifier used here, mark it used *)
if depend then
tp^.tsym^.lused := true
end
else begin
(* identifier declared in enclosing
scope, mark it used *)
tp^.tsym^.lused := true
end;
555:
end;
ngoto:
if not islocal(tp^.tlabel) then
begin
tp^.tlabel^.tsym^.lgo := true;
usejmps := true;
cklevel(tp^.tlabel)
end;
nbreak,
npush,
npop,
npredef,
nempty,
nchar,
ninteger,
nreal,
nstring,
nnil:
end;(* case *)
tp := tp^.tnext
end
end; (* global *)
(* Rename identifiers identical to C keywords. *)
procedure renamc;
var ip : idptr;
cn : cnames;
begin
(* rename identifiers that mustn't be redefined
if C and Pascal semantix are to be preserved *)
for cn := cabort to cwrite do
begin
ip := mkrename('C', ctable[cn]);
ctable[cn]^.istr := ip^.istr
end
end;
(* Rename subroutines declared in other subroutines such *)
(* that they can be moved to a global scope without name- *)
(* clashes. *)
procedure renamp(tp : treeptr; on : boolean);
var sp : symptr;
begin
(* tp points to subroutine-list *)
while tp <> nil do
begin
renamp(tp^.tsubsub, true);
if on and (tp^.tsubstmt <> nil) then
begin
(* change name of subroutine by prefixing
a unique name *)
sp := tp^.tsubid^.tsym;
if sp^.lid^.inref > 1 then
begin
sp^.lid := mkrename('P', sp^.lid);
sp^.lid^.inref := sp^.lid^.inref - 1
end
end;
tp := tp^.tnext
end
end;
(* Add initialization-code for file-variables. *)
procedure initcode(tp : treeptr);
var ti, tq, tu, tv : treeptr;
(* Determine if a type contains a file. *)
function filevar(tp : treeptr) : boolean;
var fv : boolean;
tq : treeptr;
begin
case tp^.tt of
npredef:
fv := tp = typnods[ttext];
nfileof:
fv := true;
nconfarr:
fv := filevar(typeof(tp^.tcelem));
narray:
fv := filevar(typeof(tp^.taelem));
nrecord:
begin
fv := false;
tq := tp^.tvlist;
while tq <> nil do
begin
if filevar(tq^.tvrnt) then
error(evrntfile);
tq := tq^.tnext
end;
tq := tp^.tflist;
while tq <> nil do
begin
if filevar(typeof(tq^.tbind)) then
begin
fv := true;
tq := nil
end
else
tq := tq^.tnext
end
end;
nptr:
begin
fv := false;
if not tp^.tptrflag then
begin
tp^.tptrflag := true;
if filevar(typeof(tp^.tptrid)) then
error(evarfile);
tp^.tptrflag := false
end
end;
nsubrange,
nscalar,
nsetof:
fv := false
end;
filevar := fv
end;
(* Create code for initialization of files. *)
function fileinit(ti, tq : treeptr; opn : boolean) : treeptr;
var tx, ty, tz : treeptr;
begin
(* create 1 statement initializing "ti" *)
case tq^.tt of
narray:
begin
(* create declaration for a loopvariable *)
tz := newid(mkvariable('I'));
ty := mknode(nvar);
ty^.tattr := aregister;
ty^.tidl := tz;
ty^.tbind := typeof(tq^.taindx);
tz := tq;
while not(tz^.tt in [nproc, nfunc, npgm]) do
tz := tz^.tup;
linkup(tz, ty);
if tz^.tsubvar = nil then
tz^.tsubvar := ty
else begin
tz := tz^.tsubvar;
while tz^.tnext <> nil do
tz := tz^.tnext;
tz^.tnext := ty
end;
ty := ty^.tidl;
(* create a loop initializing tq *)
tz := mknode(nindex);
tz^.tvariable := ti;
tz^.toffset := ty;
tz := fileinit(tz, tq^.taelem, opn);
tx := mknode(nfor);
tx^.tforid := ty;
ty := typeof(tq^.taindx);
if ty^.tt = nsubrange then
begin
tx^.tfrom := ty^.tlo;